package com.tips {
	import config.TConfig;
	
	import flash.display.DisplayObject;
	import flash.display.InteractiveObject;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;
	
	import org.aswing.util.HashMap;

	/**
	 * 管理鼠标提示.
	 * @author tamt
	 * @version 2009/12/31
	 */
	public class TipsManager extends EventDispatcher {
		private static var _instance : TipsManager;

		public static function getInstance() : TipsManager {
			if(_instance == null) {
				_instance = new TipsManager(new SingletonEnforcer);
			}
			return _instance;
		}

		private var _tipsRender : HashMap;
		private var _tipPanel : TipPanel;
		//正在显示那个显示对象的鼠标提示.
		private var _showingTarget : DisplayObject;
		//
		private var _dockTimer : Timer;

		public function TipsManager(se : SingletonEnforcer) : void {
		}

		private var _stage :Sprite;

		public function setStage(stage :Sprite) : void {
			_stage = stage;
		}

		/**
		 * 当前提示是哪个显示对象的。
		 */
		public function getCurTipTrigger() : DisplayObject {
			return _showingTarget;
		}

		/**
		 * 顯示tip面板。設計這個函數的主要目的：不通過滑鼠經過而顯示tip的情況，比如：StarsMapViewer中MapTile的tip的顯示機制。
		 * @param addToTipPanel		加入到tip面板的東東。
		 */
		public function showTipPanel(addToTipPanel : DisplayObject, pt : Point = null) : void {
			if(_tipPanel == null) {
				_tipPanel = new TipPanel();
				_tipPanel.addEventListener(MouseEvent.ROLL_OUT, onRollOutTip);
				//-----------[悬停计时]------------
				this.setDockTimer();
				//------------------------------
			}
			
			_tipPanel.clear();
			_tipPanel.addChild(addToTipPanel);
			_stage.addChild(_tipPanel);
			
			if(pt) {
				_tipPanel.setPos(pt.x, pt.y);
			} else {
				_tipPanel.setPos(_stage.mouseX, _stage.mouseY);
			}
		}

		/**
		 * 刪除tip面板的顯示
		 */
		public function removeTipPanel() : void {
			if(_tipPanel.parent && !_tipPanel.docked && !_tipPanel.isMouseOn) {
				_tipPanel.parent.removeChild(_tipPanel);
				//-------[悬停计时]--------
				stopDockTimer();
				//----------------------
			}
		}

		/**
		 * 设置一个显示对象的tip
		 * @param target		显示对象.
		 * @param tipRenderer	tip的渲染器.(函数, 首个参数必须是tipPanel:TipPanel).
		 * @param cachAsBmp		tip绘制后用位图
		 * @param args			提供给tipRenderer的参数.
		 */
		public function setTipRenderer(target : DisplayObject, tipRenderer : Function, cachAsBmp : Boolean = true, ...args) : void {
			if(_tipsRender == null)_tipsRender = new HashMap();
			if(_tipsRender.containsKey(target)) {
				_tipsRender.put(target, new TipCommand(tipRenderer, args, cachAsBmp, (target as InteractiveObject).mouseEnabled));
			} else {
				_tipsRender.put(target, new TipCommand(tipRenderer, args, cachAsBmp, (target as InteractiveObject).mouseEnabled));
				target.addEventListener(Event.ADDED_TO_STAGE, onTargetAdded, false, 0, true);
				target.addEventListener(Event.REMOVED_FROM_STAGE, onTargetRemoved, false, 0, true);
				if(target.stage) {
					target.addEventListener(MouseEvent.ROLL_OVER, onTargetRollOver, false, 0, true);
					target.addEventListener(MouseEvent.ROLL_OUT, onTargetRollOut, false, 0, true);
				}
			}
			(target as InteractiveObject).mouseEnabled = true;
		}

		/**
		 * 删除一个显示对象的鼠标提示
		 */
		public function delTipRenderer(target : DisplayObject) : void {
			if(_tipsRender == null)return;
			if(_tipsRender.containsKey(target)) {
				var tc : TipCommand = _tipsRender.get(target);
				(target as InteractiveObject).mouseEnabled = tc.mouseEnabled;
				_tipsRender.remove(target);
				
				target.removeEventListener(Event.ADDED_TO_STAGE, onTargetAdded);
				target.removeEventListener(Event.REMOVED_FROM_STAGE, onTargetRemoved);
				target.removeEventListener(MouseEvent.ROLL_OVER, onTargetRollOver);
				target.removeEventListener(MouseEvent.ROLL_OUT, onTargetRollOut);
			}
		}

		/**
		 * 更新tip的显示.
		 * @param target 		要显示tip的显示对象. 必须时调用过setTipRenderer设置过该显示对象.
		 */
		public function updateTip(target : DisplayObject) : void {
			if(_tipPanel == null)return;
			if(target == _tipPanel.target) {
				if(_tipsRender.containsKey(target)) {
					//判断是否鼠标在目前的物体上，如果在的话，就更新
					var cmd : TipCommand = _tipsRender.get(target);
					var render : Function = cmd.fun;
					render.apply(target, [_tipPanel].concat(cmd.args));
				}
			}
		}

		/**
		 * 目标加进舞台
		 */
		private function onTargetAdded(evt : Event) : void {
			var target : DisplayObject;
			if(_tipsRender.containsKey(evt.target)) {
				target = evt.target as DisplayObject;
				//				target.addEventListener(Event.REMOVED_FROM_STAGE, onTargetRemoved, false, 0, true);
				target.addEventListener(MouseEvent.ROLL_OVER, onTargetRollOver, false, 0, true);				target.addEventListener(MouseEvent.ROLL_OUT, onTargetRollOut, false, 0, true);
			}
		}

		/**
		 * 目标被移除舞台
		 */
		private function onTargetRemoved(evt : Event) : void {
			if(_tipsRender.containsKey(evt.target)) {
				//			evt.target.removeEventListener(Event.REMOVED_FROM_STAGE, onTargetRemoved);
				evt.target.removeEventListener(MouseEvent.ROLL_OVER, onTargetRollOver);
				evt.target.removeEventListener(MouseEvent.ROLL_OUT, onTargetRollOut);
			
				if(_showingTarget == evt.target) {
					onTargetRollOut();
				}
			}
		}

		/**
		 * 鼠标经过目标时, 显示tip
		 */
		private function onTargetRollOver(evt : MouseEvent) : void {
			if(_tipPanel == null) {
				_tipPanel = new TipPanel();
				_tipPanel.addEventListener(MouseEvent.ROLL_OUT, onRollOutTip);
				//-----------[悬停计时]------------
				this.setDockTimer();
				//------------------------------
			}
			//			_tipPanel.clear();
			if(_tipsRender.containsKey(evt.target)) {
				var cmd : TipCommand = _tipsRender.get(evt.target);
				_tipPanel.target = evt.target as DisplayObject;
				var render : Function = cmd.fun;
				render.apply(evt.target, [_tipPanel].concat(cmd.args));
				_tipPanel.cacheAsBitmap = cmd.shot;
				_showingTarget = evt.target as DisplayObject;
				//-----------[悬停计时]------------
				this.setDockTimer();
				//------------------------------
				if(_stage == null) {
					if(TConfig.getInstance().mainSprite) {
						_stage = TConfig.getInstance().mainSprite;
					} else {
						if(evt.target.stage)_stage = evt.target.stage;
					}
				}
				_stage.addChild(_tipPanel);
				_tipPanel.setPos(evt.stageX, evt.stageY);
				
				_showingTarget.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false, 0, true);
			}
		}

		private function onMouseMove(evt : MouseEvent) : void {
			var tx : Number = evt.stageX;
			var ty : Number = evt.stageY;
			
			//-------[悬停计时]--------
			this.restartDockTimer();
			//----------------------

			if(_tipsRender.containsKey(_showingTarget)) {
				_tipPanel.setPos(tx, ty);
			}
//			evt.updateAfterEvent();
		}

		/**
		 * 鼠标离开目标时, 移除tip
		 */
		private function onTargetRollOut(evt : MouseEvent = null) : void {
			removeTipPanel();
			
			if(_showingTarget == null)return;
			_showingTarget.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
		}

		private function setDockTimer() : void {
			if(_tipPanel.dockDelay > 1) {
				if(_dockTimer == null) {
					_dockTimer = new Timer(_tipPanel.dockDelay);
					_dockTimer.addEventListener(TimerEvent.TIMER, onTipDock);
				}
				_dockTimer.delay = _tipPanel.dockDelay;
				if(!_dockTimer.running)_dockTimer.start();
			} else {
				if(_dockTimer) {
					if(_dockTimer.running)_dockTimer.stop();
				}
			}
		}

		private function stopDockTimer() : void {
			if(_dockTimer) {
				if(_dockTimer.running) {
					_dockTimer.stop();
				}
			}
		}

		private function restartDockTimer() : void {
			if(_dockTimer) {
				if(_dockTimer.running) {
					_dockTimer.reset();
					_dockTimer.start();
				}
			}
		}

		private function onTipDock(evt : TimerEvent) : void {
			_dockTimer.reset();
			//			_showingTarget.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			_tipPanel.onDock();
		}

		private function onRollOutTip(evt : MouseEvent) : void {
			_tipPanel.onUnDock();
			if(_showingTarget == null) {
				//-------[悬停计时]--------
				stopDockTimer();
				//----------------------
				_tipPanel.parent.removeChild(_tipPanel);
			}
		}
	}
}

class SingletonEnforcer {
}

class TipCommand {
	public var fun : Function;
	public var args : Array;
	/**
	 * 是否拍照
	 */
	public var shot : Boolean = true;
	//
	public var mouseEnabled : Boolean = false;

	public function TipCommand(fun : Function, args : Array,shot : Boolean = true, mouseEnabled : Boolean = false) : void {
		this.fun = fun;
		this.args = args;
		this.shot = shot;
		this.mouseEnabled = mouseEnabled;
	}
}